﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.ComponentModel;
using Skin2D.Control;
using Skin2D.Display;
using Skin2D.Control.LogSystem;

namespace Skin2D.Bone
{

    class Bone2D 
    {

        public Bone2D(Bone2D parent)
        {
            Parent = parent;
            m_relative = new Matrix();
            m_absolute = new Matrix();
            m_translate = new PointF(0, 0);
            m_rotate_angle = 0;
            m_length = 30;
            m_childs = new List<Bone2D>();
            ID = Bone2D.m_Id++;
            Selected = false;
           
        }

        //--------------------------------------------------------------------------//
        //                          Matrix Property                                 //
        //--------------------------------------------------------------------------//
        public void UpdateAbsolute()
        {
            m_relative = new Matrix();
            m_relative.Translate(m_translate.X, m_translate.Y);
            m_relative.Rotate(m_rotate_angle);

            if (Parent != null)
            {
                m_absolute = Parent.AbsoulteMatrix;

            }
            else
            {
                m_absolute = new Matrix();
            }

            m_absolute.Multiply(m_relative);


            //Update Bound box
            Matrix tmp= m_absolute.Clone();
            PointF[] rec = new PointF[]{ new PointF(0,0),new PointF(Length,0) };
            tmp.TransformPoints(rec);
            float top_x = rec[0].X < rec[1].X ? rec[0].X : rec[1].X;
            float top_y = rec[0].Y < rec[1].Y ? rec[0].Y : rec[1].Y;
            m_boundBox = new RectangleF(top_x, top_y, Math.Abs(rec[1].X - rec[0].X), Math.Abs(rec[1].Y - rec[0].Y));
            
        }



        public PointF getTranslate()
        {
            return new PointF(m_relative.OffsetX, m_relative.OffsetY);
        }

        public void setTranslate(PointF offset)
        {
            m_translate = offset;
        }

        public void setTranslate(float x, float y)
        {
            m_translate = new PointF(x, y);
        }

        public void setRotate(float angle)
        {
            m_rotate_angle = angle;
        }

        public float getRotate()
        {
            
            return m_rotate_angle;
        }

        public void setLength(float lenght)
        {
            m_length = lenght;
        }

        public double getAbsoluteRotate()
        {
            float[] tmp = this.AbsoulteMatrix.Elements;

            double val = Math.Acos(tmp[0])*180 / Math.PI;
            return val;
        }

        public PointF getAbsouluteTranslate()
        {
            Matrix tmp = this.AbsoulteMatrix;
            return new PointF(tmp.OffsetX, tmp.OffsetY);
        }

        [BrowsableAttribute(false)]
        public Matrix AbsoulteMatrix
        {
            get
            {
                UpdateAbsolute();
                return m_absolute;
            }
        }
        //--------------------------------------------------------------------------//
        //                                  Childs                                  //
        //--------------------------------------------------------------------------//

        public void AddChild(Bone2D bone)
        {
            if (bone != null)
                m_childs.Add(bone);
        }

        public void AddChild(Bone2D bone, int index)
        {
            if (bone != null)
            {
                m_childs.Insert(index, bone);
            }
        }

        public int RemoveChild(Bone2D bone)
        {
            int index = m_childs.FindIndex(p => p == bone);
            if (bone != null)
                m_childs.Remove(bone);

            return index;
        }

        public List<Bone2D> Childs()
        {
            return m_childs;
        }


        //--------------------------------------------------------------------------//
        //                                  Display                                 //
        //--------------------------------------------------------------------------//
        public void Draw(ref System.Drawing.Graphics g,Pen pen)
        {
          
           

            if (Selected)
            {
                g.Transform = new Matrix();
                DisplayDriver.Get().CameraTransform();
                g.DrawRectangle(Pens.Blue, m_boundBox.X, m_boundBox.Y, m_boundBox.Width, m_boundBox.Height);
                pen.Color = Color.Blue;
            }

            g.Transform = this.AbsoulteMatrix;
            DisplayDriver.Get().CameraTransform();
            g.DrawLine(pen, 0, 0, this.Length, 0);

            if (Selected)
            {
                pen.Color = Color.Red;
            }

            foreach (Bone2D item in m_childs)
            {
                item.Draw(ref g, pen);
            }
        }

        //--------------------------------------------------------------------------//
        //                             Data Members                                 //
        //--------------------------------------------------------------------------//

        [ReadOnlyAttribute(true), DescriptionAttribute("Parent Bone ID")]
        public Bone2D Parent { get; private set; }

        [CategoryAttribute("Properties"), DescriptionAttribute("Bone Length")]
        private float m_length;
        public float Length
        {
            get
            {
                return m_length;
            }
            set
            {
                EventLog.AddLog("Length", this, m_length);
                m_length = value;
            }
        }

        [ReadOnlyAttribute(true), DescriptionAttribute("Bone ID")]
        public int ID { get; set; }

        [CategoryAttribute("Properties"), DescriptionAttribute("Relative Translation"), TypeConverter(typeof(PointFConverter))]
        public PointF RelativeTranslate
        {
            get
            {
                return m_translate;
            }
            set
            {
                EventLog.AddLog("RelativeTranslate", this, m_translate);
                setTranslate(value);

            }
        }

        [CategoryAttribute("Properties"), DescriptionAttribute("Relative Rotation")]
        public float RelativeRotation
        {
            get
            {
                return m_rotate_angle;
            }
            set
            {
                EventLog.AddLog("RelativeRotation", this, m_rotate_angle);
                setRotate(value);

            }
        }

        [BrowsableAttribute(false)]
        public bool Selected { get; set; }

        public override string ToString()
        {
            return "Bone " + ID.ToString();
        }

        public RectangleF getBoundBox()
        {
            return m_boundBox;
        }

        private List<Bone2D> m_childs;
        private float  m_rotate_angle;
        private PointF m_translate;
        private Matrix m_absolute;
        private Matrix m_relative;

        private RectangleF m_boundBox;

        private static int m_Id = 0;
    }
}
